package com.neusoft.hifly.commons.lang;

import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.time.LocalDate;

import org.apache.commons.lang3.StringUtils;

/**
 * Title: 核心类库
 * <p>
 * Description: 反射工具类
 * <p>
 * Copyright: 2019
 * <p>
 * Company: 东软汉枫
 *
 * @author lh_neu
 * @version 1.0.0
 */
public class ReflectionUtil {

	//所有的系统类型
	private static final String[] DEF_TYPE = new String[] { "java.lang.String", "java.lang.Long", "long",
			"java.lang.Integer", "int", "java.lang.Short", "short", "java.lang.Byte", "byte", "java.lang.Float",
			"float", "java.lang.Double", "double", "java.util.Date", "java.lang,Char", "char", "java.lang.Boolean",
			"boolean", "java.sql.Timestamp" };

	/**
	 * 新建实例
	 *
	 * @param className
	 *            类名
	 * @param args
	 *            构造函数的参数
	 * @return 新建的实例
	 * @throws Exception
	 *             异常
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static Object newInstance(final String className, final Object[] args) throws Exception {
		if (StringUtils.isNotEmpty(className) && args != null) {
			// 得到要构造的实例的Class
			final Class newoneClass = Class.forName(className);
			// 得到参数的Class数组
			final Class[] argsClass = new Class[args.length];
			for (int i = 0, j = args.length; i < j; i++) {
				argsClass[i] = args[i].getClass();
			}
			// 得到构造子
			final Constructor cons = newoneClass.getConstructor(argsClass);
			// 新建实例
			return cons.newInstance(args);
		} else {
			return null;
		}
	}

	/**
	 * 判断是否为某个类的实例
	 *
	 * @param obj
	 *            实例
	 * @param cls
	 *            类
	 * @return 如果 obj 是此类的实例，则返回 true
	 */
	@SuppressWarnings("rawtypes")
	public static boolean isInstance(final Object obj, final Class cls) {
		if (obj != null && cls != null) {
			return cls.isInstance(obj);
		} else {
			return false;
		}
	}

	/**
	 * 执行某对象方法
	 *
	 * @param owner
	 *            对象
	 * @param methodName
	 *            方法名
	 * @param args
	 *            参数
	 * @return 方法返回值(set方法没有返回值，get方法有返回值)
	 * @throws Exception
	 *             异常
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static Object invokeMethod(final Object owner, final String methodName, final Object[] args)
			throws Exception {
		if (owner != null && StringUtils.isNotEmpty(methodName) && args != null) {
			// 配置参数的Class数组，作为寻找Method的条件。
			final Class ownerClass = owner.getClass();
			final Class[] argsClass = new Class[args.length];
			for (int i = 0, j = args.length; i < j; i++) {
				argsClass[i] = args[i].getClass();
			}
			// 通过Method名和参数的Class数组得到要执行的Method。
			final Method method = ownerClass.getMethod(methodName, argsClass);
			// 执行该Method，invoke方法的参数是执行这个方法的对象，和参数数组。返回值是Object，也既是该方法的返回值。
			return method.invoke(owner, args);
		} else {
			return null;
		}
	}

	/**
	 * 执行某对象方法
	 *
	 * @param owner
	 *            对象
	 * @param methodName
	 *            方法名
	 * @param methodType
	 *            方法类型
	 * @param value
	 *            参数
	 * @return 方法返回值(set方法没有返回值，get方法有返回值)
	 * @throws Exception
	 *             异常
	 */
	public static Object setMethod(final Object owner, final String methodName, final String methodType, Object value)
			throws Exception {
		if (owner != null && StringUtils.isNotEmpty(methodName)) {
			// 配置参数的Class数组，作为寻找Method的条件。
			final Class<?> ownerClass = owner.getClass();

			Class<?> argsClass = String.class;

			if (StringUtils.isNotEmpty(methodType)) {
				switch (methodType) {
					case "Integer":
						argsClass = Integer.class;
						if (String.valueOf(value).endsWith(".0")) {
							value = Integer.parseInt(String.valueOf(value).replace(".0", ""));
						} else {
							value = Integer.parseInt(String.valueOf(value));
						}
						break;
					case "Float":
						argsClass = Float.class;
						value = Float.parseFloat(String.valueOf(value));
						break;
					case "LocalDate":
						argsClass = LocalDate.class;
						value = LocalDateUtil.strToDate(String.valueOf(value));
						break;
					default:
						break;
				}
			}

			// 通过Method名和参数的Class数组得到要执行的Method。
			final Method method = ownerClass.getMethod(methodName, argsClass);
			// 执行该Method，invoke方法的参数是执行这个方法的对象，和参数数组。返回值是Object，也既是该方法的返回值。
			return method.invoke(owner, value);
		} else {
			return null;
		}
	}

	/**
	 * 执行某类的静态方法
	 *
	 * @param className
	 *            类名
	 * @param methodName
	 *            方法名
	 * @param args
	 *            参数数组
	 * @return 执行方法返回的结果
	 * @throws Exception
	 *             异常
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static Object invokeStaticMethod(final String className, final String methodName, final Object[] args)
			throws Exception {
		if (StringUtils.isNotEmpty(methodName) && StringUtils.isNotEmpty(className) && args != null) {
			final Class ownerClass = Class.forName(className);
			final Class[] argsClass = new Class[args.length];
			for (int i = 0, j = args.length; i < j; i++) {
				argsClass[i] = args[i].getClass();
			}
			// invoke的一个参数是null，因为这是静态方法，不需要借助实例运行。
			final Method method = ownerClass.getMethod(methodName, argsClass);
			return method.invoke(null, args);
		} else {
			return null;
		}
	}

	/**
	 * 得到数组中的某个元素
	 *
	 * @param array
	 *            数组
	 * @param index
	 *            索引
	 * @return 返回指定数组对象中索引组件的值
	 */
	public static Object getByArray(final Object array, final int index) {
		if (array != null) {
			return Array.get(array, index);
		} else {
			return null;
		}
	}

	/**
	 * 得到某个对象的公共属性
	 *
	 * @param owner
	 *            对象
	 * @param fieldName
	 *            公共属性名称
	 * @return 该属性对象
	 * @throws Exception
	 *             异常
	 */
	public static Object getProperty(final Object owner, final String fieldName) throws Exception {
		if (owner != null && StringUtils.isNotEmpty(fieldName)) {
			// 得到该对象的Class。
			final Class<? extends Object> ownerClass = owner.getClass();
			// 返回已加载类声明的所有成员变量的Field对象,包括从父类继承的成员变量,参数name指定成员变量的名称.
			final Field field = ownerClass.getField(fieldName);
			// 通过对象得到该属性的实例，如果这个属性是非公有的，这里会报IllegalAccessException。
			return field.get(owner);
		} else {
			return null;
		}
	}

	/**
	 * 得到某类的静态公共属性
	 *
	 * @param className
	 *            类名
	 * @param fieldName
	 *            属性名
	 * @return 该属性对象
	 * @throws Exception
	 *             异常
	 */
	public static Object getStaticProperty(final String className, final String fieldName) throws Exception {
		if (StringUtils.isNotEmpty(className) && StringUtils.isNotEmpty(fieldName)) {
			// 首先得到这个类的Class
			final Class<?> ownerClass = Class.forName(className);
			// 和上面一样，通过Class得到类声明的属性
			final Field field = ownerClass.getField(fieldName);
			// 这里和上面有些不同，因为该属性是静态的，所以直接从类的Class里取
			return field.get(ownerClass);
		} else {
			return null;
		}
	}

	/**
	 * 通过get方法得到某个对象属性的值
	 *
	 * @param owner
	 *            对象
	 * @param fieldName
	 *            属性名称
	 * @return 该属性对象的值
	 */
	public static Object getMethod(final Object owner, String fieldName) {
		if (owner != null && StringUtils.isNotEmpty(fieldName)) {
			final Class<? extends Object> ownerClass = owner.getClass();
			Object objRtn = null;
			if (ownerClass != null) {
				// 判断该属性的类型
				final Field[] fieldlist = ownerClass.getDeclaredFields();
				String fieldType = null;
				for (final Field field : fieldlist) {
					if (field.getName().equals(fieldName)) {
						fieldType = field.getType().getName();
						break;
					}
				}

				//属性名的第一个字母大写，与get或者is组成方法名
				final String firstCharUpper = fieldName.substring(0, 1).toUpperCase()
						+ fieldName.substring(1, fieldName.length());

				//如果是boolean型则方法名为is*；反之为get*
				if (ReflectionUtil.isBooleanType(fieldType)) {
					fieldName = "is" + firstCharUpper;
				} else {
					fieldName = "get" + firstCharUpper;
				}
				try {
					// 通过getMethod()获取一个方法，这里setMethod被附值一个方法名setName
					final Method methodGet = ownerClass.getMethod(fieldName);
					if (methodGet != null) {
						// invoke()方法，将属性name的值取出，相当于getXxx();。提示：invoke()是取值还是附值看getMethod()取回的值
						objRtn = methodGet.invoke(owner);
					}
				} catch (final Exception e) {
					return null;
				}
			}
			return objRtn;
		} else {
			return null;
		}
	}

	/**
	 * 判断是否是逻辑类型
	 *
	 * @param fieldType
	 *            类型
	 * @return 是否逻辑类型
	 */
	public static boolean isBooleanType(final String fieldType) {
		if ("java.util.Boolean".equalsIgnoreCase(fieldType) || "boolean".equalsIgnoreCase(fieldType)) {
			return true;
		}
		return false;
	}

	/**
	 * 验证属性的类型是否是系统定义的类型
	 *
	 * @param fieldType
	 *            待验证类型的名称
	 * @return true 是系统定义的对象 false 用户定义的对象
	 */
	public static boolean isSysDefinedType(final String fieldType) {
		for (final String type : ReflectionUtil.DEF_TYPE) {
			if (fieldType.equals(type)) {
				return true;
			}
		}
		return false;
	}

}
